package org.unidata.mdm.meta.type.model.attributes;

import static org.unidata.mdm.meta.type.model.ModelNamespace.META_MODEL_NAMESPACE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.core.type.model.source.CustomProperty;
import org.unidata.mdm.meta.type.model.MetaModelAttribute;
import org.unidata.mdm.meta.type.model.ValueGenerationStrategy;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;


@JsonPropertyOrder({
    "customProperties",
    "valueGenerationStrategy"})
public abstract class AbstractMetaModelAttribute<X extends AbstractMetaModelAttribute<X>> implements MetaModelAttribute {
    /**
     * GSVUID.
     */
    private static final long serialVersionUID = -895730513135421368L;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private List<CustomProperty> customProperties;

    @JacksonXmlProperty(namespace = META_MODEL_NAMESPACE)
    private ValueGenerationStrategy valueGenerationStrategy;

    @JacksonXmlProperty(isAttribute = true)
    private String name;

    @JacksonXmlProperty(isAttribute = true)
    private String displayName;

    @JacksonXmlProperty(isAttribute = true)
    private String description;

    @JacksonXmlProperty(isAttribute = true)
    private boolean readOnly;

    @JacksonXmlProperty(isAttribute = true)
    private boolean hidden;

    @Override
    public List<CustomProperty> getCustomProperties() {
        if (customProperties == null) {
            customProperties = new ArrayList<>();
        }
        return this.customProperties;
    }

    @Override
    public void setCustomProperties(List<CustomProperty> customProperties) {
        withCustomProperties(customProperties);
    }

    @Override
    public ValueGenerationStrategy getValueGenerationStrategy() {
        return valueGenerationStrategy;
    }

    @Override
    public void setValueGenerationStrategy(ValueGenerationStrategy value) {
        this.valueGenerationStrategy = value;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String value) {
        this.name = value;
    }

    @Override
    public String getDisplayName() {
        return displayName;
    }

    @Override
    public void setDisplayName(String value) {
        this.displayName = value;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public void setDescription(String value) {
        this.description = value;
    }

    @Override
    public boolean isReadOnly() {
        return readOnly;
    }

    @Override
    public void setReadOnly(boolean value) {
        this.readOnly = value;
    }

    @Override
    public boolean isHidden() {
        return hidden;
    }

    @Override
    public void setHidden(boolean value) {
        this.hidden = value;
    }

    public X withCustomProperties(CustomProperty... values) {
        if (ArrayUtils.isNotEmpty(values)) {
            Collections.addAll(getCustomProperties(), values);
        }
        return self();
    }

    public X withCustomProperties(Collection<CustomProperty> values) {
        if (CollectionUtils.isNotEmpty(values)) {
            getCustomProperties().addAll(values);
        }
        return self();
    }

    public X withValueGenerationStrategy(ValueGenerationStrategy value) {
        setValueGenerationStrategy(value);
        return self();
    }

    public X withName(String value) {
        setName(value);
        return self();
    }

    public X withDisplayName(String value) {
        setDisplayName(value);
        return self();
    }

    public X withDescription(String value) {
        setDescription(value);
        return self();
    }

    public X withReadOnly(boolean value) {
        setReadOnly(value);
        return self();
    }

    public X withHidden(boolean value) {
        setHidden(value);
        return self();
    }

    @SuppressWarnings("unchecked")
    protected X self() {
        return (X) this;
    }
}
